/*
 * caixa_eletronicoImpl.java
 *
 * Created on November 7, 2007, 4:30 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package banco;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import org.omg.CORBA.DoubleHolder;

/**
 *
 * @author das
 */
public class caixa_eletronicoImpl extends caixa_eletronicoPOA{
    
    /** Tipos de Transacoes */
    private final int POUPANCA = 0;
    private final int FUNDO_ACOES = 1;
    private final int RENDA_FIXA = 2;
    private final int SAQUE = 3;
    private final int TRANSF_DEBITO = 4;
    private final int TRANSF_CREDITO = 5;
    
    /* gerenciadores da conexao com o banco */
    private Connection bdConn;
    private Statement statement;
    
    /* pretende armazenar o resultado da query SQL */
    private ResultSet resultSetQuery;
    
    /** Creates a new instance of caixa_eletronicoImpl */
    public caixa_eletronicoImpl () {
        try {
            
            /** Driver JDBC */
            Class.forName ("com.mysql.jdbc.Driver");
            
            /** Estancia da Conexao com o Banco: driver:banco://local/basedados, login, senha */
            bdConn = DriverManager.getConnection ("jdbc:mysql://localhost/bancin", "root", "root");
            
            /** Pega Statement... */
            statement = bdConn.createStatement ();
            
        } catch (Exception e) {
            System.err.println ("Erro MySql: " + e);
            e.printStackTrace ();
        }
    }
    
    public String boas_vindas () {
        // this might not work :)
        return "Bem-vindo ao banco " + banco.nome_banco.value;
    }
    
    public double saldo (int c) throws conta_inval {
        try {
            resultSetQuery = statement.executeQuery ( "SELECT saldo FROM conta WHERE numero = " + c );
            if(!resultSetQuery.first ()) {
                throw new banco.conta_inval ( c );
            }
        } catch( SQLException e ) {
            System.err.println ( "Conta inexistente: " + e );
            e.printStackTrace ();
            throw new banco.conta_inval ( c );
        }
        try {
            
            return resultSetQuery.getDouble ( "saldo" );
        } catch (SQLException ex) {
            ex.printStackTrace ();
            throw new conta_inval (c);
        }
    }
    
    public void extrato (int c, transacoesHolder t, DoubleHolder saldo) throws conta_inval {
        try {
            /* pega valor do saldo */
            resultSetQuery = statement.executeQuery ( "SELECT saldo FROM conta WHERE numero = " + c );
            if( resultSetQuery.first () ) {
                /* seta valor do saldo para retorno */
                saldo.value = resultSetQuery.getDouble ( "saldo" );
                
                /* pega entradas na tabela historico das transacoes */
                resultSetQuery = statement.executeQuery ( "SELECT * FROM historico WHERE numero_conta LIKE " + c );
                /* verifica se ha alguma entrada na tabela */
                if( resultSetQuery.first () ) {
                    /* avança para a ultima linha para contar qtas linhas sao */
                    resultSetQuery.last ();
                    
                    int
                            numTransacoes = resultSetQuery.getRow ();
                    
                    resultSetQuery.first ();
                    
                    
                    transacao[] transacoes = new transacao[ numTransacoes ];
                    
                    
                    for( int i = 0; i < numTransacoes; i++ ) {
                        Timestamp tstamp = resultSetQuery.getTimestamp ( "data" );
                        java.text.SimpleDateFormat formato = new java.text.SimpleDateFormat ("ddMMyyyy");
                        String stringData = formato.format (tstamp);
                        
                        transacao
                                tr = new transacao ();
                        
                        tr.data = Integer.parseInt (stringData);
                        
                        tr.quantia = resultSetQuery.getDouble ("valor");
                        
                        /* supondo que as aplicacoes e operações estejam sendo inseridas deste jeito no bd */
                        switch( resultSetQuery.getInt ("tipo_aplicacao") ) {
                            case POUPANCA:
                                tr.descricao = "Poupanca";
                                break;
                            case FUNDO_ACOES:
                                tr.descricao = "Fundo Acoes";
                                break;
                            case RENDA_FIXA:
                                tr.descricao = "Renda Fixa";
                                break;
                            case SAQUE:
                                tr.descricao = "Saque";
                                break;
                            case TRANSF_DEBITO:
                                tr.descricao = "Tranf debito";
                                break;
                            case TRANSF_CREDITO:
                                tr.descricao = "Tranf credit";
                        }
                        
                        /* adiciona transacao no vetor de transacoes */
                        transacoes[i] = tr;
                        
                        /* avanca para a proxima linha */
                        resultSetQuery.next ();
                    }
                    /* atribui as transacaoes a variavel de retorno */
                    t.value = transacoes;
                } else {
                    System.out.println ( "Não há registros de transações nesta conta" );
                }
            } else {
                throw new banco.conta_inval ( c );
            }
        } catch( SQLException e ) {
            System.err.println ( "Conta inexistente: " + e );
            e.printStackTrace ();
            throw new banco.conta_inval ( c );
        }
    }
    
    public void tranferencia (int origem, int destino, double v) throws conta_inval, saldo_insuf {
        /**
         * 1. Verificar se conta de origem existe
         * 2. Verificar se existe saldo para realizar a transferencia
         * 3. Verificar se existe conta de destino
         * 4. Salvar novo saldo da conta de origem
         * 5. Salvar novo saldo da conta de destino
         * 6. Salvar o debito no historico
         * 7. Salvar o credito no historico
         */
        
        try /* Executando passo 1. Verificar se conta de origem existe */
        {
            resultSetQuery = statement.executeQuery ("SELECT saldo FROM conta WHERE numero = " + origem);
            /* _resultSet.first()_ move o cursor para a primeira linha válida
              do retorno da query, assim, se o retorno for vazio, _first()_
              retornara falso */
            if(!resultSetQuery.first ()) {
                throw new banco.conta_inval ( origem );
            }
        }catch(SQLException e) {
            System.err.println ("Conta fonte da transferencia inexistente: " + e);
            e.printStackTrace ();
            throw new banco.conta_inval (e.getMessage (), origem); // Que que eh isso meu Deus? denovo? pra onde vai? PQ?
        }
        double saldo = 0.0;
        try {
            saldo = resultSetQuery.getDouble ("saldo");
        } catch (SQLException ex) {
            ex.printStackTrace ();
        }
        
        if( saldo < v) {
            throw new banco.saldo_insuf ("Saldo Insuficiente para realizar operação", saldo);
        }
        
        double saldoDestino = 0.0;
        
        try /* Executando passo 3. Verificar se existe conta de destino */
        {
            resultSetQuery = statement.executeQuery ("SELECT saldo FROM conta WHERE numero = " + origem);
            /* _resultSet.first()_ move o cursor para a primeira linha válida
              do retorno da query, assim, se o retorno for vazio, _first()_
              retornara falso */
            if(!resultSetQuery.first ()) {
                throw new banco.conta_inval ( origem );
            } else {
                saldoDestino = resultSetQuery.getDouble ("saldo");
            }
        }catch(SQLException e) {
            System.err.println ("Conta de destino da transferencia inexistente: " + e);
            e.printStackTrace ();
            throw new banco.conta_inval (e.getMessage (), origem); // Que que eh isso meu Deus? denovo? pra onde vai? PQ?
        }
        try {
            
            /* Executando passo 4. Salvar novo saldo da conta de origem  */
            statement.execute ("UPDATE conta SET saldo = " + (saldo - v) + " WHERE numero = " + origem);
            
            /* Executando passo 5. Salvar novo saldo da conta de destino */
            statement.execute ("UPDATE conta SET saldo = " + (saldoDestino + v) + " WHERE numero = " + destino);
            /* Executando passo 6. Salvar o debito no historico */
            statement.execute ("INSERT INTO historico (numero_conta, tipo_aplicacao, valor) " +
                    "VALUES ("+ origem + ", " + TRANSF_DEBITO + " , "+ v + ")" );
            /* Executando passo 7. Salvar o credito no historico */
            statement.execute ("INSERT INTO historico (numero_conta, tipo_aplicacao, valor) " +
                    "VALUES ("+ destino + ", " + TRANSF_CREDITO + " , "+ v + ")" );
            
        } catch (SQLException ex) {
            ex.printStackTrace ();
        }
    }
    
    public void saque (int c, double v) throws conta_inval, saldo_insuf {	/**
     * 1. Verificar se conta existe
     * 2. Verificar se existe saldo para realizar o saque
     * 3. Salvar o novo saldo
     * 4. Salvar no historico
     */
        try {
            resultSetQuery = statement.executeQuery ("SELECT saldo FROM conta WHERE numero = " + c);
            /* _resultSet.first()_ move o cursor para a primeira linha válida
              do retorno da query, assim, se o retorno for vazio, _first()_
              retornara falso */
            if(!resultSetQuery.first ()) {
                throw new banco.conta_inval ( c );
            }
        }catch(SQLException e) {
            System.err.println ("Conta inexistente: " + e);
            e.printStackTrace ();
            throw new banco.conta_inval (e.getMessage (), c); // Que que eh isso meu Deus? denovo? pra onde vai? PQ?
        }
        
        double saldo = 0.0;
        try {
            saldo = resultSetQuery.getDouble ("saldo");
        } catch (SQLException ex) {
            ex.printStackTrace ();
        }
        
        try {
            if( saldo < v) {
                throw new banco.saldo_insuf ("Saldo Insuficiente para realizar operação", saldo);
            } else {
                statement.execute ("UPDATE conta SET saldo = " + (saldo - v) + " WHERE numero = " + c);
                statement.execute ("INSERT INTO historico (numero_conta, tipo_aplicacao, valor) " +
                        "VALUES ("+ c + ", " + SAQUE + " , "+ v + ")" );
            }
        }catch( SQLException e ) {
            System.err.println ( "Saldo Insuficiente: " + e );
            e.printStackTrace ();
        }
    }
    
    public void investimento (int c, aplicacao apl, double v) throws conta_inval, saldo_insuf {
        /** Para realizar um investimento verificamos o tipo primeiro,
         *  depois soma-se ao valor na conta do banco de dados
         *  * banco.aplicacao e um enum com {poupanca, fundo_acoes, renda_fixa}
         */
        int opcaoInvestimento = banco.aplicacao.poupanca.value ();
        double saldoAtual = 0;
        
        if (opcaoInvestimento < 0 || opcaoInvestimento > 2) {
            System.err.println ("Erro paramentro em investimento(): valor de banco.aplicacao nao e valido.");
            throw new banco.conta_inval ("Opcao de Investimento INVALIDA.", c);
        }
        
        try {
            resultSetQuery = statement.executeQuery ("SELECT saldo FROM conta WHERE numero = "+c);
            resultSetQuery.first ();
            
        } catch(SQLException e) {
            System.err.println ("Conta inexistente: " + e);
            e.printStackTrace ();
            throw new banco.conta_inval (e.getMessage (), c);
        }
        
        try {
            saldoAtual = resultSetQuery.getDouble ("saldo");
            
            /** Verifica se saldo e maior ou igual ao valor do investimento */
            if (saldoAtual < v) {
                /* se nao for, retorna erro de saldo_insuf */
                throw new banco.saldo_insuf ("Saldo Insuficiente para realizar operação", saldoAtual);
                
            } else {
                
                statement.execute ("UPDATE conta SET saldo = " + (saldoAtual - v) + " WHERE numero = " + c);
                
                statement.execute ("INSERT INTO aplicacao VALUES ("+ c +","+ opcaoInvestimento +","+ v +")");
                
                statement.execute ("INSERT INTO historico (numero_conta, tipo_aplicacao, valor) " +
                        "VALUES ("+ c +","+ opcaoInvestimento +","+ v +")");
                
            }
        } catch (SQLException e) {
            System.err.println ("Aplicação não realizada, erro no banco: " + e);
            e.printStackTrace ();
            // retorno de exception SQL, deveria ter uma definição de excessao de
            // erro de SQL no idl, tipo o banco.conta_inval e saldo_insuf.
            throw new banco.saldo_insuf ("Erro ao alterar conta "+c+": " +
                    e.getMessage (), saldoAtual);
        }
    }
}
